#!/usr/bin/env python3
"""
数据可视化模块 - 独立图表版本
负责生成各种独立的高清图表
"""

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
from typing import Optional, List, Dict, Any
import os
from wordcloud import WordCloud
import jieba
import logging

from .analyzer import DataAnalyzer

logger = logging.getLogger('Visualizer')


class Visualizer:
    """可视化器 - 负责数据可视化"""
    
    def __init__(self, analyzer: DataAnalyzer):
        """
        初始化可视化器
        
        Args:
            analyzer: 数据分析器实例
        """
        self.analyzer = analyzer
        self.setup_style()
        logger.info("可视化器初始化完成")
    
    def setup_style(self):
        """设置可视化样式"""
        import matplotlib as mpl
        from matplotlib import font_manager
        
        try:
            # 清除字体缓存
            font_manager._rebuild()
            
            # 获取系统中所有字体
            system_fonts = [f.name for f in font_manager.fontManager.ttflist]
            logger.info(f"系统可用字体数量: {len(system_fonts)}")
            
            # 中文字体优先级列表
            chinese_fonts_priority = [
                'SimHei', 'Microsoft YaHei', 'DejaVu Sans', 
                'WenQuanYi Micro Hei', 'Noto Sans CJK SC', 'Source Han Sans CN',
                'PingFang SC', 'Hiragino Sans GB', 'STHeiti', 'SimSun',
                'Arial Unicode MS'
            ]
            
            # 找到第一个可用的中文字体
            selected_font = None
            for font_name in chinese_fonts_priority:
                if font_name in system_fonts:
                    selected_font = font_name
                    logger.info(f"选择字体: {selected_font}")
                    break
            
            if selected_font:
                # 设置字体
                plt.rcParams['font.family'] = selected_font
                plt.rcParams['font.sans-serif'] = [selected_font] + plt.rcParams['font.sans-serif']
            else:
                logger.warning("未找到中文字体，尝试使用字体文件")
                # 尝试直接使用字体文件
                font_path = self._get_font_path()
                if font_path:
                    try:
                        # 直接添加字体文件到字体管理器
                        font_prop = font_manager.FontProperties(fname=font_path)
                        plt.rcParams['font.family'] = [font_prop.get_name()]
                        logger.info(f"使用字体文件: {font_path}")
                    except Exception as e:
                        logger.error(f"加载字体文件失败: {e}")
            
            # 确保设置生效
            plt.rcParams['axes.unicode_minus'] = False
            
            # 测试字体
            self._test_chinese_font()
            
        except Exception as e:
            logger.error(f"字体设置失败: {e}")
            # 备用设置
            plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'Arial']
            plt.rcParams['axes.unicode_minus'] = False
        
        sns.set_style("whitegrid")
        sns.set_palette("husl")
        
        # 提高图表清晰度设置
        plt.rcParams['figure.figsize'] = [12, 8]
        plt.rcParams['figure.dpi'] = 300
        plt.rcParams['savefig.dpi'] = 300
        plt.rcParams['font.size'] = 12
        plt.rcParams['axes.titlesize'] = 16
        plt.rcParams['axes.labelsize'] = 14
        plt.rcParams['xtick.labelsize'] = 12
        plt.rcParams['ytick.labelsize'] = 12
    
    def plot_engagement_distribution(self, save_path: Optional[str] = None) -> bool:
        """
        绘制互动量分布图 - 独立图表
        
        Args:
            save_path: 保存路径
            
        Returns:
            是否成功生成
        """
        if self.analyzer.df.empty:
            logger.warning("没有数据可可视化")
            return False
        
        try:
            # 创建独立图表
            fig, ax = plt.subplots(figsize=(12, 8))
            
            df = self.analyzer.df
            
            # 互动量分布直方图
            n, bins, patches = ax.hist(
                df['total_engagement'], 
                bins=20, 
                alpha=0.7, 
                color='#1f77b4', 
                edgecolor='black',
                linewidth=1.2
            )
            
            ax.set_title('微博互动量分布', fontsize=18, fontweight='bold', pad=20)
            ax.set_xlabel('总互动量', fontsize=14)
            ax.set_ylabel('频次', fontsize=14)
            ax.grid(True, alpha=0.3)
            
            # 添加统计信息
            mean_engagement = df['total_engagement'].mean()
            median_engagement = df['total_engagement'].median()
            max_engagement = df['total_engagement'].max()
            
            # 在图表上添加统计信息
            stats_text = f'平均互动量: {mean_engagement:.1f}\n中位数: {median_engagement:.1f}\n最大值: {max_engagement:.1f}'
            ax.text(0.95, 0.95, stats_text, transform=ax.transAxes, 
                   verticalalignment='top', horizontalalignment='right',
                   bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8),
                   fontsize=12)
            
            plt.tight_layout()
            
            if save_path:
                plt.savefig(save_path, dpi=300, bbox_inches='tight', 
                           facecolor='white', edgecolor='none')
                logger.info(f"互动量分布图已保存至: {save_path}")
            
            plt.show()
            return True
            
        except Exception as e:
            logger.error(f"生成互动量分布图失败: {e}")
            return False
    
    def plot_engagement_type_distribution(self, save_path: Optional[str] = None) -> bool:
        """
        绘制互动类型分布饼图 - 独立图表
        
        Args:
            save_path: 保存路径
            
        Returns:
            是否成功生成
        """
        if self.analyzer.df.empty:
            logger.warning("没有数据可可视化")
            return False
        
        try:
            # 创建独立图表
            fig, ax = plt.subplots(figsize=(10, 8))
            
            df = self.analyzer.df
            
            # 互动类型对比
            engagement_types = ['转发', '评论', '点赞']
            engagement_values = [
                df['reposts_count'].sum(),
                df['comments_count'].sum(),
                df['likes_count'].sum()
            ]
            
            colors = ['#ff6b6b', '#4ecdc4', '#45b7d1']
            
            # 绘制饼图
            wedges, texts, autotexts = ax.pie(
                engagement_values, 
                labels=engagement_types, 
                autopct=lambda pct: f'{pct:.1f}%\n({int(pct * sum(engagement_values) / 100)})',
                startangle=90,
                colors=colors,
                textprops={'fontsize': 12}
            )
            
            # 美化百分比文本
            for autotext in autotexts:
                autotext.set_color('white')
                autotext.set_fontweight('bold')
                autotext.set_fontsize(11)
            
            ax.set_title('微博互动类型分布', fontsize=18, fontweight='bold', pad=20)
            
            # 添加图例
            ax.legend(wedges, engagement_types, title="互动类型", loc="center left", 
                     bbox_to_anchor=(1, 0, 0.5, 1))
            
            plt.tight_layout()
            
            if save_path:
                plt.savefig(save_path, dpi=300, bbox_inches='tight', 
                           facecolor='white', edgecolor='none')
                logger.info(f"互动类型分布图已保存至: {save_path}")
            
            plt.show()
            return True
            
        except Exception as e:
            logger.error(f"生成互动类型分布图失败: {e}")
            return False
    
    def plot_text_length_vs_engagement(self, save_path: Optional[str] = None) -> bool:
        """
        绘制文本长度与互动量关系图 - 独立图表
        
        Args:
            save_path: 保存路径
            
        Returns:
            是否成功生成
        """
        if self.analyzer.df.empty:
            logger.warning("没有数据可可视化")
            return False
        
        try:
            # 创建独立图表
            fig, ax = plt.subplots(figsize=(12, 8))
            
            df = self.analyzer.df
            
            # 文本长度与互动量关系散点图
            scatter = ax.scatter(
                df['content_length'], 
                df['total_engagement'], 
                alpha=0.6, 
                color='#9c27b0',
                s=60,  # 点的大小
                edgecolors='black',
                linewidth=0.5
            )
            
            ax.set_title('文本长度与互动量关系', fontsize=18, fontweight='bold', pad=20)
            ax.set_xlabel('文本长度（字符数）', fontsize=14)
            ax.set_ylabel('总互动量', fontsize=14)
            ax.grid(True, alpha=0.3)
            
            # 添加趋势线
            if len(df) > 1:
                z = np.polyfit(df['content_length'], df['total_engagement'], 1)
                p = np.poly1d(z)
                trend_line = ax.plot(
                    df['content_length'], 
                    p(df['content_length']), 
                    "r--", 
                    alpha=0.8,
                    linewidth=2,
                    label='趋势线'
                )
                ax.legend()
            
            # 计算相关系数
            correlation = df['content_length'].corr(df['total_engagement'])
            ax.text(0.95, 0.95, f'相关系数: {correlation:.3f}', 
                   transform=ax.transAxes, verticalalignment='top', 
                   horizontalalignment='right',
                   bbox=dict(boxstyle='round', facecolor='lightgray', alpha=0.8),
                   fontsize=12)
            
            plt.tight_layout()
            
            if save_path:
                plt.savefig(save_path, dpi=300, bbox_inches='tight', 
                           facecolor='white', edgecolor='none')
                logger.info(f"文本长度与互动量关系图已保存至: {save_path}")
            
            plt.show()
            return True
            
        except Exception as e:
            logger.error(f"生成文本长度与互动量关系图失败: {e}")
            return False
    
    def plot_top_users_engagement(self, save_path: Optional[str] = None, top_n: int = 10) -> bool:
        """
        绘制用户互动量TOP图表 - 独立图表
        
        Args:
            save_path: 保存路径
            top_n: 显示前N名用户
            
        Returns:
            是否成功生成
        """
        if self.analyzer.df.empty:
            logger.warning("没有数据可可视化")
            return False
        
        try:
            # 创建独立图表
            fig, ax = plt.subplots(figsize=(14, 10))
            
            df = self.analyzer.df
            
            # 热门用户TOP N
            if 'user_name' in df.columns:
                user_engagement = df.groupby('user_name')['total_engagement'].sum().nlargest(top_n)
                
                if not user_engagement.empty:
                    y_pos = np.arange(len(user_engagement))
                    
                    # 使用渐变色
                    colors = plt.cm.viridis(np.linspace(0, 1, len(user_engagement)))
                    
                    bars = ax.barh(y_pos, user_engagement.values, color=colors, alpha=0.8, height=0.7)
                    
                    ax.set_yticks(y_pos)
                    ax.set_yticklabels(user_engagement.index, fontsize=11)
                    ax.set_title(f'用户互动量TOP {top_n}', fontsize=18, fontweight='bold', pad=20)
                    ax.set_xlabel('总互动量', fontsize=14)
                    
                    # 在条形图上添加数值
                    for i, (bar, value) in enumerate(zip(bars, user_engagement.values)):
                        ax.text(
                            value + max(user_engagement.values) * 0.01, 
                            bar.get_y() + bar.get_height()/2,
                            f'{int(value):,}',  # 千分位分隔符
                            va='center', 
                            ha='left',
                            fontsize=11,
                            fontweight='bold'
                        )
                    
                    # 添加网格线
                    ax.grid(True, axis='x', alpha=0.3)
                    ax.set_axisbelow(True)
                    
                    # 反转y轴，使最高的在顶部
                    ax.invert_yaxis()
                    
                    # 美化边框
                    for spine in ax.spines.values():
                        spine.set_visible(False)
                else:
                    ax.text(0.5, 0.5, '无用户数据', ha='center', va='center', 
                           transform=ax.transAxes, fontsize=16)
                    ax.set_title('用户互动量TOP 10', fontsize=18, fontweight='bold')
            else:
                ax.text(0.5, 0.5, '无用户名字段', ha='center', va='center', 
                       transform=ax.transAxes, fontsize=16)
                ax.set_title('用户互动量TOP 10', fontsize=18, fontweight='bold')
            
            plt.tight_layout()
            
            if save_path:
                plt.savefig(save_path, dpi=300, bbox_inches='tight', 
                           facecolor='white', edgecolor='none')
                logger.info(f"用户互动量TOP图已保存至: {save_path}")
            
            plt.show()
            return True
            
        except Exception as e:
            logger.error(f"生成用户互动量TOP图失败: {e}")
            return False
    
    def generate_wordcloud(self, save_path: Optional[str] = None) -> bool:
        """
        生成词云图 - 独立高清版本
        
        Args:
            save_path: 保存路径
            
        Returns:
            是否成功生成
        """
        if self.analyzer.df.empty:
            logger.warning("没有数据生成词云")
            return False
        
        try:
            # 合并所有文本
            text = ' '.join(self.analyzer.df['content'].dropna())
            
            if not text.strip():
                logger.warning("没有有效的文本数据生成词云")
                return False
            
            # 使用jieba分词
            words = ' '.join(jieba.cut(text))
            
            # 生成高清词云
            wordcloud = WordCloud(
                font_path=self._get_font_path(),
                width=1600,  # 提高分辨率
                height=1200,
                background_color='white',
                max_words=150,  # 增加词汇量
                colormap='viridis',
                contour_width=2,
                contour_color='steelblue',
                relative_scaling=0.5,
                min_font_size=10,
                max_font_size=200,
                random_state=42  # 确保可重复性
            ).generate(words)
            
            plt.figure(figsize=(16, 12))
            plt.imshow(wordcloud, interpolation='bilinear')
            plt.axis('off')
            plt.title('微博内容词云分析', fontsize=20, fontweight='bold', pad=30)
            
            if save_path:
                plt.savefig(save_path, dpi=300, bbox_inches='tight', 
                           facecolor='white', edgecolor='none')
                logger.info(f"词云图已保存至: {save_path}")
            
            plt.show()
            return True
            
        except Exception as e:
            logger.error(f"生成词云图失败: {e}")
            return False
    
    def _get_font_path(self) -> str:
        """获取中文字体路径"""
        # 尝试常见的中文字体路径
        font_paths = [
            '/System/Library/Fonts/PingFang.ttc',  # macOS
            '/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf',  # Linux
            'C:/Windows/Fonts/simhei.ttf',  # Windows
            'C:/Windows/Fonts/msyh.ttc',    # 微软雅黑
            'simhei.ttf'  # 当前目录
        ]
        
        for font_path in font_paths:
            if os.path.exists(font_path):
                return font_path
        
        return None
    
    def _test_chinese_font(self):
        """测试中文字体是否正常工作"""
        try:
            fig, ax = plt.subplots(figsize=(6, 2))
            ax.text(0.5, 0.5, '中文测试', transform=ax.transAxes, 
                   ha='center', va='center', fontsize=20)
            ax.axis('off')
            plt.close(fig)  # 不显示，只是测试
            logger.info("中文字体测试通过")
        except Exception as e:
            logger.warning(f"中文字体测试失败: {e}")
    
    def create_individual_charts(self, output_dir: str = 'visualizations') -> bool:
        """
        创建所有独立的高清图表
        
        Args:
            output_dir: 输出目录
            
        Returns:
            是否成功生成
        """
        import matplotlib as mpl
        mpl.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
        mpl.rcParams['axes.unicode_minus'] = False
        try:
            os.makedirs(output_dir, exist_ok=True)
            
            # 定义要生成的图表列表
            charts = [
                ('engagement_distribution.png', self.plot_engagement_distribution),
                ('engagement_type_distribution.png', self.plot_engagement_type_distribution),
                ('text_length_vs_engagement.png', self.plot_text_length_vs_engagement),
                ('top_users_engagement.png', self.plot_top_users_engagement),
                ('wordcloud.png', self.generate_wordcloud)
            ]
            
            success_count = 0
            for filename, plot_func in charts:
                filepath = os.path.join(output_dir, filename)
                if plot_func(filepath):
                    success_count += 1
                    logger.info(f"成功生成: {filename}")
                else:
                    logger.warning(f"生成失败: {filename}")
            
            logger.info(f"独立图表生成完成，成功生成 {success_count}/{len(charts)} 个图表")
            return success_count > 0
            
        except Exception as e:
            logger.error(f"创建独立图表失败: {e}")
            return False

    # 保留原有的综合图表函数，但标记为不建议使用
    def plot_engagement_analysis(self, save_path: Optional[str] = None) -> bool:
        """
        绘制综合互动分析图（不建议使用，请使用独立的图表函数）
        """
        logger.warning("不建议使用综合图表，请使用独立的图表函数")
        return False